/*
 * Copyright (C) 2011-2021 ShenZhen iBOXCHAIN Information Technology Co.,Ltd.
 *
 * All right reserved.
 *
 * This software is the confidential and proprietary
 * information of iBOXCHAIN Company of China.
 * ("Confidential Information"). You shall not disclose
 * such Confidential Information and shall use it only
 * in accordance with the terms of the contract agreement
 * you entered into with iBOXCHAIN inc.
 *
 */
package cn.anoxia.springframework.beans.factory.xml;

import cn.anoxia.springframework.beans.BeansException;
import cn.anoxia.springframework.beans.PropertyValue;
import cn.anoxia.springframework.beans.factory.BeanDefinition;
import cn.anoxia.springframework.beans.factory.BeanReference;
import cn.anoxia.springframework.beans.support.AbstractBeanDefinitionReader;
import cn.anoxia.springframework.beans.support.BeanDefinitionRegistry;
import cn.anoxia.springframework.core.io.Resource;
import cn.anoxia.springframework.core.io.ResourceLoader;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.util.Assert;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.InputStream;

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

  public XmlBeanDefinitionReader(BeanDefinitionRegistry registry){
    super(registry);
  }

  public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
    super(registry, resourceLoader);
  }

  @Override
  public void loadBeanDefinitions(Resource resource) throws BeansException {

    try {
      try(InputStream inputStream = resource.getInputStream()){
        doLoadBeanDefinitions(inputStream);
      }
    }catch (Exception e){
      throw new BeansException("解析文件xml 获取inputstream流失败 " + resource, e);
    }

  }

  @Override
  public void loadBeanDefinitions(Resource... resources) throws BeansException {
    for (Resource resource: resources){
      loadBeanDefinitions(resource);
    }
  }

  @Override
  public void loadBeanDefinitions(String location) throws BeansException {
    ResourceLoader resourceLoader = getResourceLoader();
    Resource resource = resourceLoader.getResource(location);
    loadBeanDefinitions(resource);
  }

  @Override
  public void loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException, BeansException {
    Assert.notNull(locations, "Location array must not be null");
    for (String location : locations) {
      loadBeanDefinitions(location);
    }
  }

  protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException, BeansException {
    Document document = XmlUtil.readXML(inputStream);
    Element element = document.getDocumentElement();
    NodeList childNodes = element.getChildNodes();
    for (int i = 0; i < childNodes.getLength(); i++) {
      // 判断元素
      if (!(childNodes.item(i) instanceof Element)) {
        continue;
      }
      // 判断对象
      if (!"bean".equals(childNodes.item(i).getNodeName())) {
        continue;
      }

      // 解析标签
      Element bean = (Element) childNodes.item(i);
      String id = bean.getAttribute("id");
      String name = bean.getAttribute("name");
      String className = bean.getAttribute("class");
      String initMethodName = bean.getAttribute("init-method");
      String destroyMethodName = bean.getAttribute("destroy-method");
      // 获取 Class，方便获取类中的名称
      Class<?> clazz = Class.forName(className);
      // 优先级 id > name
      String beanName = StrUtil.isNotEmpty(id) ? id : name;
      if (StrUtil.isEmpty(beanName)) {
        beanName = StrUtil.lowerFirst(clazz.getSimpleName());
      }
      // 定义Bean
      BeanDefinition beanDefinition = new BeanDefinition(clazz);
      // 设置初始化方法和销毁方法
      if (StrUtil.isNotBlank(initMethodName)){
        beanDefinition.setInitMethodName(initMethodName);
      }
      if (StrUtil.isNotBlank(destroyMethodName)){
        beanDefinition.setDestroyMethodName(destroyMethodName);
      }
      // 读取属性并填充
      for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
        if (!(bean.getChildNodes().item(j) instanceof Element)) {
          continue;
        }
        if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) {
          continue;
        }
        // 解析标签：property
        Element property = (Element) bean.getChildNodes().item(j);
        String attrName = property.getAttribute("name");
        String attrValue = property.getAttribute("value");
        String attrRef = property.getAttribute("ref");
        // 获取属性值：引入对象、值对象
        Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
        // 创建属性信息
        PropertyValue propertyValue = new PropertyValue(attrName, value);
        beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
      }
      if (getRegistry().containsBeanDefinition(beanName)) {
        throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
      }
      // 注册 BeanDefinition
      getRegistry().registerBeanDefinition(beanName, beanDefinition);
    }
  }
}
